package com.achobeta.recruitment.service.impl.wx;

import com.achobeta.recruitment.config.QRCodeConstant;
import com.achobeta.recruitment.message.Article;
import com.achobeta.recruitment.message.ImageMessage;
import com.achobeta.recruitment.message.NewsMessage;
import com.achobeta.recruitment.message.TextMessage;
import com.achobeta.recruitment.model.WxUser;
import com.achobeta.recruitment.service.wx.WxService;
import com.achobeta.recruitment.service.wx.WxUserService;
import com.achobeta.recruitment.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 马拉圈
 * Date: 2023-10-26
 * Time: 11:43
 */

@Service
@Slf4j
public class WxServiceImpl implements WxService {


    // 注入token
    @Value("${wx.token}")
    private String token;

    @Value("${redirect.domain}")
    private String redirectDomain;


    @Value("${redirect.fe}")
    private String redirectFE;

    @Value("${wx.appid}")
    private String appId;

    @Value("${wx.secret}")
    private String secret;

    @Value("${recruit.resume.url}")
    private String resume;

    @Autowired
    private WxUserService wxUserService;
    /**
     *  检查是否是微信服务器发来的请求
     * @param signature
     * @param timestamp
     * @param nonce
     * @param echostr
     * @return 非回显字符串的其他都视为不通过
     */

    @Override
    public String check(String signature, String timestamp, String nonce, String echostr) {
        String[] list = {token, timestamp, nonce};
        Arrays.sort(list);
        // 2) 将三个字符串以此顺序进行拼接
         StringBuilder builder = new StringBuilder();
        for(String s : list) {
            builder.append(s);
        }
        // 2.1) 加密
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("sha1");
            byte[] digest = messageDigest.digest(builder.toString().getBytes(StandardCharsets.UTF_8));
            // 2.2) 将加密后的byte数组转换为signature一样的格式（每个字节都转换为十六进制进行拼接）
            builder = new StringBuilder();
            for(byte b : digest) {
                // builder.append(Integer.toHexString(b));不能这么弄因为这样弄b如果是负，那么就凉凉
                // 这样写保证两位十六进制都存在并且正确
                builder.append(Integer.toHexString((b >> 4) & 15));//前四个字节转换为十六进制
                builder.append(Integer.toHexString(b & 15));//后四个字节转换为十六进制
            }
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
        // 3) 核对请求是否来自于微信（加密解析后的字符串与signature比较）
        if(builder.toString().equals(signature)) {
            // 相同才返回回显字符串
            // 并且返回echostr代表开发者确认了这是公众号服务器发来的请求，公众号就进行配置
            System.out.println("成功 ： " + echostr);
            return echostr;
        } else {
            // 否则返回null
            return null;
        }
    }

    /*
    引导裂变用户访问地址进行授权，之后改用模版消息来封装
*/
    public String createSignUpRedirectUri(Map<String, Object> map) {
        //获得关注者的信息（微信号、昵称、头像等）并存入微信号昵称对应表
        //先引导用户访问地址进行授权，之后改用模版消息来封装、
        String url = "https://open.weixin.qq.com/connect/oauth2/authorize" + HttpUtils.getQueryString(new HashMap<String, Object>() {{
            this.put("appid", appId);
            this.put("redirect_uri", redirectDomain + "/wxuser/getSignUpUserInfo");
            this.put("scope", "snsapi_userinfo");
            this.put("response_type", "code");
        }}) + "#wechat_redirect";
        System.out.println(url);
        map.put("Content", "点击链接：<a href=\"" + url + "\">报名</a>");
        TextMessage textMessage = TextMessage.getReplyTextMessage(map);
        return XmlUtils.objectToXml(textMessage);
    }


    @Override
    public String handleMessage(Map<String, Object> map) {

        String message = "";
        String MsgType = (String) map.get("MsgType");
        if ("event".equals(MsgType)) {
            message = handleEvent(map);//处理事件
        } else {
            log.info("其他消息类型，暂时无法处理：" + MsgType);
        }
//        System.out.println(message);
        return message;
    }

    /**
     * 处理事件类型的消息
     * @param map
     * @return
     */
    private String handleEvent(Map<String, Object> map) {

        String message = "";
        // 获取event值
        String event = (String) map.get("Event");
        // 事件分支
        switch (event) {
            case "CLICK":
                message = handleClick(map);
                break;
            case "VIEW":
                log.info("用户跳转页面：" + map.get("EventKey"));
                break;
            case "subscribe":
                message = handleSubscribeEvent(map);
                break;
            default:
                log.info("触发其他事件，当前不能处理：" + event);
                break;
        }
        return message;
    }

    /**
     * 处理用户关注的消息
     * @param map
     * @return
     */
    private String
    handleSubscribeEvent(Map<String, Object> map) {
        map.put("Content", "感谢你的关注，AchoBeta最近举办了招新活动，快点击报名参加吧！😊");
        TextMessage textMessage = TextMessage.getReplyTextMessage(map);
        return XmlUtils.objectToXml(textMessage);
    }

    /**
     * 处理用户点击的消息
     * @param map
     * @return
     */
    private String handleClick(Map<String, Object> map) {
        String message = "";
        String key = (String) map.get("EventKey");
        switch (key) {
            case "1":
                message = getRecruitNewsMessage(map);
//                message = createSignUpRedirectUri(map);
                break;
            case "2":
                message = getUniqueQRCode(map);
                break;
            case "3":
                message = getPoster(map);
                break;
            default:
                log.info("暂时无法处理按钮" + key);
                break;
        }
        return message;
    }

    private String getPoster(Map<String, Object> map) {
        // 上传资源
        String mediaId = MediaUtils.sendMedia(QRCodeConstant.DOWNLOAD_PATH_PREFIX + QRCodeConstant.BACKGROUND_POSTER_NAME
                , appId, secret);
        // 构造返回消息
        ImageMessage imageMessage = ImageMessage.getImageMessage(map, mediaId);
        return XmlUtils.objectToXml(imageMessage);
    }


    /**
     * 获取专属二维码
     * @param map
     * @return
     */
    private String getUniqueQRCode(Map<String, Object> map) {
        String fromUserName = (String) map.get("FromUserName");
        // 检测用户是否存在，并获取微信用户信息 -----
        WxUser wxUser = wxUserService.selectWxUserByOpenid(fromUserName);
        if(wxUser == null) {
            return "";
        }
        String forPath = QRCodeConstant.DOWNLOAD_PATH_PREFIX + fromUserName + "_full.png";
        if(new File(forPath).exists()) {
            // 上传合成的图片到微信服务器
            String mediaId = MediaUtils.sendMedia(forPath, appId, secret);
            // 合并图片资源返回
            ImageMessage imageMessage = ImageMessage.getImageMessage(map, mediaId);
            return XmlUtils.objectToXml(imageMessage);
        }
        String url = redirectFE + resume + HttpUtils.getQueryString(new HashMap<String, Object>() {{
            this.put("openid", fromUserName);
        }});
//        String url = "http://mason.nat100.top/hello.html";
        String qrPath = QRCodeGenerator.loadQRCode(url);
        String headImgUrl = wxUser.getWxPhoto();
        String mergeImgPath = MediaUtils.mergeImage(qrPath, headImgUrl, fromUserName);
        // 上传合成的图片到微信服务器
        String mediaId = MediaUtils.sendMedia(mergeImgPath, appId, secret);
        // 合并图片资源返回
        ImageMessage imageMessage = ImageMessage.getImageMessage(map, mediaId);
        return XmlUtils.objectToXml(imageMessage);
    }


    /**
     * 获取图文推送消息
     * @param map
     * @return
     */
    private String getRecruitNewsMessage(Map<String, Object> map) {
        String fromUserName = (String) map.get("FromUserName");
        WxUser wxUser = wxUserService.selectWxUserByOpenid(fromUserName);
        if(wxUser == null) {
            return "";
        }
        Article article = new Article();
        article.setTitle("填写简历");
        article.setUrl(redirectFE + resume + HttpUtils.getQueryString(new HashMap<String, Object>() {{
            this.put("openid", fromUserName);
        }}));
//        article.setUrl("http://mason.nat100.top/hello.html");

        article.setPicUrl(wxUser.getWxPhoto());
        article.setDescription("简历信息填写草稿");
        NewsMessage replyNewsMessage = NewsMessage.getReplyNewsMessage(map, article);
        return XmlUtils.objectToXml(replyNewsMessage);
    }
}
